package org.fing.edu.uy.esbadp.motor.comunication;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.logging.Level;

import org.fing.edu.uy.esbadp.core.AdpFlowInterface;
import org.fing.edu.uy.esbadp.core.AdpFlowSYNC;
import org.fing.edu.uy.esbadp.core.AdpFlowTree;
import org.fing.edu.uy.esbadp.core.constants.ConfigConstants;
import org.fing.edu.uy.esbadp.core.constants.EsbAdpServiceMetadataKeys;
import org.fing.edu.uy.esbadp.core.constants.JMXServiceConstants;
import org.fing.edu.uy.esbadp.core.entity.DMRegisteredService;
import org.fing.edu.uy.esbadp.core.entity.GenericTreeNode;
import org.fing.edu.uy.esbadp.core.utils.JMXManager;
import org.fing.edu.uy.esbadp.logger.LoggerADP;
import org.fing.edu.uy.esbadp.motor.config.MgrConfig;
import org.fing.edu.uy.esbadp.validation.ValidateArgument;

public class AdmAdaptationComunication {
	
	 private static java.util.logging.Logger logger = LoggerADP.getLogger(AdmAdaptationComunication.class.getSimpleName());
		
	
	/**
	 * Funcion encargarda de obtener el AdpFlow actual del servicio que se esta monitoreando actualmente, dicho AdpFlow
	 * se obtiene del Administrador de Adpataciones.
	 * @return AdpFlowTree Retorna la adaptacion que posse actualmente, en caso de no existir retorna null.
	 * @throws Exception En caso de error al invocar la operacion JMX retorna error.
	 */
	public static AdpFlowTree getActualAdpFlow(Long serviceId) throws Exception {
		//config call operations getAdpFlowForService
		String jmxServiceURL = MgrConfig.getInstance().getProperty(ConfigConstants.JMXEsbAdpURL);
		String mBeanName = JMXServiceConstants.JMXAdmAdaptationMBean;
		Object[] arguments = {serviceId};
		String[] signature = {Long.class.getName()};
		//result to return
		AdpFlowTree adpFlowTree = null;
		
		//get actual adaptation
		Object result = JMXManager.callOperation(jmxServiceURL, mBeanName, "getAdpFlowForService", arguments, signature);
		if(result != null){
			adpFlowTree = (AdpFlowTree) result;
		}else{
			logger.log(Level.INFO, "There is no registration for the tree service {0}.", serviceId );
		}
		
		return adpFlowTree;
	}
	
	
	
	/**
	 * Funcion encargada de setear el nuevo arbol.
	 * @param tree
	 * @throws Exception En caso de error al invocar la operacion JMX retorna error.
	 */
	public static void setAdpFlowForService(Long serviceId,GenericTreeNode<AdpFlowInterface> rootNode) throws Exception {
		//config call operations getAdpFlowForService
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.add(Calendar.SECOND, Integer.parseInt(MgrConfig.getInstance().getProperty(ConfigConstants.STRATEGY_EXPIRATION_TIME, "300")));
		
		String enableHistoricFlowString = MgrConfig.getInstance().getProperty(ConfigConstants.HISTORIC_ENABLE, "false");
		boolean historic_enable =  Boolean.parseBoolean(enableHistoricFlowString);
		
		AdpFlowTree flowTree = new AdpFlowTree();
		flowTree.setExpiredDate(calendar.getTime());
		flowTree.setFlowTree(rootNode);
		flowTree.setServiceID(serviceId);	
		flowTree.setSaveHistoric(historic_enable);
		
		String jmxServiceURL = MgrConfig.getInstance().getProperty(ConfigConstants.JMXEsbAdpURL);
		String mBeanName = JMXServiceConstants.JMXAdmAdaptationMBean;
		Object[] arguments = {flowTree, serviceId};
		String[] signature = {AdpFlowTree.class.getName(), Long.class.getName()};		
		//set new adaptation
		JMXManager.callOperation(jmxServiceURL, mBeanName, "setAdpFlowForService", arguments, signature);		
	}
	
	
	/**
	 * Funcion encaragda de obtener el nodo del arbol para invocar al servicio virtual, SYNC
	 * @return GenericTreeNode<AdpFlowInterface> Retorna el nodo para invocar al servicio virtual.
	 * @throws Exception En caso de error al invocar la operacion JMX retorna error.
	 */
	public static GenericTreeNode<AdpFlowInterface> getAdpNodeForInvokeVirtualService(DMRegisteredService service) throws Exception {
        AdpFlowInterface actionSYNC;
        if(service.containsMetadata(EsbAdpServiceMetadataKeys.dataService) &&
                        service.getMetadata(EsbAdpServiceMetadataKeys.dataService).trim().equalsIgnoreCase("true")){
        	String ttlString = service.getMetadata(EsbAdpServiceMetadataKeys.dataCacheTTL,EsbAdpServiceMetadataKeys.dataCacheTTLDefaultValue);
            String ttidleStirng = service.getMetadata(EsbAdpServiceMetadataKeys.dataCacheTTIDLE,EsbAdpServiceMetadataKeys.dataCacheTTIDLEDefaultValue);                                   
            long ttlDef = Long.parseLong(ttlString);
            long ttIdleDef = Long.parseLong(ttidleStirng);
                                    
            if(ValidateArgument.isNotNullAndNotEmpty(ttlString)){
            	ttlDef = Integer.parseInt(ttlString);
            }
                                    
            if(ValidateArgument.isNotNullAndNotEmpty(ttidleStirng)){
                ttIdleDef = Integer.parseInt(ttidleStirng);
            }
            actionSYNC = new AdpFlowSYNC(service.getVirtualServiceName(), service.getVirtualServiceCategory(), true, ttlDef, ttIdleDef, service.getServiceID());
        }else{
            actionSYNC = new AdpFlowSYNC(service.getVirtualServiceName(), service.getVirtualServiceCategory(), false, 0, 0, service.getServiceID());
        }
        GenericTreeNode<AdpFlowInterface> SYNCNode = new GenericTreeNode<AdpFlowInterface>();
        SYNCNode.setData(actionSYNC);
        return SYNCNode;
	}

}
